AWS IoTのクイック接続を利用してPythonとMosquittoからIoT CoreとMQTT通信してみた
AWS IoTのクイック接続を利用すると、わずか15分でデバイスからSDKを使ってAWS IoT CoreとのMQTT通信できます。
このウィザードを利用し、MacBook上からPython SDKでAWS IoT CoreとMQTT通信し、作成されたリソースを流用してMosquittoクライアントからもMQTT通信してみます。
合わせて、関連するAWS IoTリソースも確認します。
前提
Mac上で以下のクライアントからAWS IoT CoreにMQTT通信します
- Python SDK
- mosquitto_pub 2.0.18
クイック接続でデバイスを簡単接続
AWS IoTのクイック接続方法は簡単です。 AWSコンソールのIoTトップページから「デバイスを接続」をクリックし、ウィザードに従ってポチポチするだけです。
Step 1 : デバイスを準備する
Macターミナルからデバイスデータエンドポイントにpingできることを確認します。 このエンドポイントは、AWSアカウント x リージョンの組み合わせごとに存在します。
同一リージョンに、複数のエンドポイントを持てないことに注意しましょう。
$ ping a1b2c3-ats.iot.ap-northeast-1.amazonaws.com PING a1b2c3-ats.iot.ap-northeast-1.amazonaws.com (54.168.193.76): 56 data bytes 64 bytes from 54.168.193.76: icmp_seq=0 ttl=245 time=26.501 ms 64 bytes from 54.168.193.76: icmp_seq=1 ttl=245 time=25.398 ms 64 bytes from 54.168.193.76: icmp_seq=2 ttl=245 time=25.524 ms ^C --- a1b2c3-ats.iot.ap-northeast-1.amazonaws.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 25.398/25.808/26.501/0.493 ms
Step 2 : デバイスを登録して保護する
AWS IoTに接続するデバイスをモノ(Thing)と表現します。
モノに名前をつけましょう。
Step 3 : プラットフォームと SDK を選択します
プラットフォームとSDKをクライアント環境に合わせます。
今回は以下の組み合わせを選択しました。
- Platform : Linux / macOS
- SDK : Python
Step 4 : 接続キットをダウンロード
Zip形式の接続キット(connect_device_package.zip
)をダウンロードします。
$ unzip -d connect_device_package connect_device_package.zip Archive: connect_device_package.zip extracting: connect_device_package/macbook.cert.pem extracting: connect_device_package/macbook.public.key extracting: connect_device_package/macbook.private.key extracting: connect_device_package/macbook-Policy extracting: connect_device_package/start.sh $ cd connect_device_package $ ls -1 TutorialTestThing-Policy TutorialTestThing.cert.pem TutorialTestThing.private.key TutorialTestThing.public.key start.sh
認証に利用されるX.509クライアント証明書を確認すると、2049年末まで有効な証明書がAmazon Trust Services(ATS)から発行されていることがわかります。
$ openssl x509 -in TutorialTestThing.cert.pem -text Certificate: Data: Version: 3 (0x2) Serial Number: d8:3a:40:6b:4f:a1:5c:0f:b8:b5:59:ac:47:89:82:99:7e:39:70:12 Signature Algorithm: sha256WithRSAEncryption Issuer: OU=Amazon Web Services O=Amazon.com Inc. L=Seattle ST=Washington C=US Validity Not Before: Jan 3 12:57:37 2024 GMT Not After : Dec 31 23:59:59 2049 GMT Subject: CN=AWS IoT Certificate Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:99:b9:c6:15:ff:7b:7f:a9:c4:f2:27:12:0b:1b: ... 53:d4:48:c7:ce:18:46:45:46:36:fa:f7:8e:16:26: 99:f1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Authority Key Identifier: 49:A8:81:2F:38:35:3B:E2:DE:A7:BA:F6:68:5E:44:A1:44:87:9F:5C X509v3 Subject Key Identifier: C4:97:88:41:6F:F6:5D:70:B9:10:C4:85:56:1B:5E:97:C7:42:04:D3 X509v3 Basic Constraints: critical CA:FALSE X509v3 Key Usage: critical Digital Signature Signature Algorithm: sha256WithRSAEncryption Signature Value: 69:9c:3c:37:7d:36:c0:e8:51:d8:73:3b:8f:ef:22:40:1b:0d: ... d3:3e:be:25:93:8a:db:53:33:28:57:c5:eb:b5:92:d6:62:ba: ec:6a:19:5a -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIVANg6QGtPoVwPuLVZrEeJgpl+OXASMA0GCSqGSIb3DQEB ... hBPdYtsoKTfFmzxO0pA2RkVjloDGhzfg0z6+JZOK21MzKFfF67WS1mK67GoZWg== -----END CERTIFICATE-----
Step 5 : 接続キットを実行
インストラクション通りにクライアントプログラムを実行すると、AWSコンソールから、サブスクライブしたメッセージを確認できます。
$ chmod +x start.sh $ ./start.sh ... Running pub/sub sample application... Connecting to a1b2c3-ats.iot.ap-northeast-1.amazonaws.com with client ID 'basicPubSub'... Connection Successful with return code: 0 session present: True Connected! Subscribing to topic 'sdk/test/python'... Subscribed with 1 Sending messages until program killed Publishing message to topic 'sdk/test/python': Hello World! [1] Received message from topic 'sdk/test/python': b'"Hello World! [1]"' Publishing message to topic 'sdk/test/python': Hello World! [2] Received message from topic 'sdk/test/python': b'"Hello World! [2]"' ...
Python Publisherスクリプトを確認
クイック接続では以下の通信を行います
- TLS通信
- MQTTプロトコル
- X.509クライアント証明書ベースの認証
- 8883ポート
起動するstart.sh
の実態は AWS IoT Coreと通信するPython スクリプト(aws-iot-device-sdk-python-v2/samples/pubsub.py
)です。
$ tail -n 1 start.sh python3 aws-iot-device-sdk-python-v2/samples/pubsub.py --endpoint a1b2c3-ats.iot.ap-southeast-2.amazonaws.com --ca_file root-CA.crt --cert macbook.cert.pem --key macbook.private.key --client_id basicPubSub --topic sdk/test/python --count 0
そのために
- AWS IoT Client SDK for Python v2 ダウンロード(
python3 -m pip install ./aws-iot-device-sdk-python-v2
) - 認証局の証明書のダウンロード(
curl https://www.amazontrust.com/repository/AmazonRootCA1.pem > root-CA.crt
)
などを行っています。
一度 start.sh
を呼び出したあとであれば、Pythonスクリプトをそのまま呼び出しても動作します。
$ python3 aws-iot-device-sdk-python-v2/samples/pubsub.py \ --endpoint a1b2c3-ats.iot.ap-northeast-1.amazonaws.com \ --ca_file root-CA.crt \ --cert TutorialTestThing.cert.pem \ --key TutorialTestThing.private.key \ --client_id basicPubSub \ --topic sdk/test/python \ --count 0
パラメーター名からそれぞれが何を表しているのかは、自明です。
MQTTにPublishするこのPythonプログラムをmosquitto_pub
に移植します。
Pythonスクリプトをmosquitto_pubに移植
Eclipse MosquittoはオープンソースのMQTTブローカーです。
MacOSからは $ brew install mosquitto
でインストールします。
mosquitto_pub
を使い、Publish用クライアントプログラムと同じ通信手順でAWS IoT Coreと通信するのが以下のコマンドです。
$ mosquitto_pub -d \ --host a1b2c3-ats.iot.ap-northeast-1.amazonaws.com \ --cafile root-CA.crt \ --cert TutorialTestThing.cert.pem \ --key TutorialTestThing.private.key \ --id basicPubSub \ --topic "sdk/test/python" \ --message '{ "message": "Hello from mosquitto_pub"}' Client basicPubSub sending CONNECT Client basicPubSub received CONNACK (0) Client basicPubSub sending PUBLISH (d0, q0, r0, m1, 'sdk/test/python', ... (41 bytes)) Client basicPubSub sending DISCONNECT
動作確認しやすいように、デバッグオプション(-d
)も渡しています。
クイック接続で利用するAWSリソースを確認
最後に、今回のクイック接続で利用した関連リソースを確認します。
AWS IoT Coreのデータプレーンエンドポイント
IoTメッセージを送受信する AWS IoT CoreのデータプレーンエンドポイントはAWSアカウントxリージョンの単位で存在します。
同じリージョンに複数のエンドポイントを用意できない、言い換えると、異なるシステムも同じエンドポイントを利用しないといけない点にご注意ください。
次のAPIからもエンドポイントを確認できます。
$ aws iot describe-endpoint --endpoint-type iot:Data-ATS { "endpointAddress": "a1b2c3-ats.iot.ap-northeast-1.amazonaws.com" }
モノ(Thing)
AWS IoTに接続するデバイスをモノ(Thing)と表現します。
コンソールでは「AWS IoT > 管理 > モノ」から確認できます。
モノの認証
モノの認証を担うのがX.509クライアント証明書です。モノと関連付けられています。
コンソールでは 「AWS IoT > セキュリティ > 証明書」 から確認できます。
クライアント接続では、「接続キットをダウンロード」のタイミングで証明書、パブリックキー、プライベートキーのセットをダウンロードしました。
コンソールからモノを新規登録する際にも、これら一式が生成されます。
また、証明書を発行する認証局の証明書は次のURLから取得できます。
https://www.amazontrust.com/repository/AmazonRootCA1.pem
モノの認可
モノの認可を担うのがポリシーです。証明書と関連付けられ、IAM PolicyのAWS IoT版とみなせます。
コンソールでは、AWS IoT > セキュリティ > ポリシー から確認できます。
クイック接続では以下のアクションが許可されています。
- iot:Publish
- iot:Receive
- iot:PublishRetain
- iot:Subscribe
- iot:Connect
iot:Connect
を例に取ると、以下の通りリソースが制限されています。
{ "Effect": "Allow", "Action": [ "iot:Connect" ], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:client/sdk-java", "arn:aws:iot:ap-northeast-1:123456789012:client/basicPubSub", "arn:aws:iot:ap-northeast-1:123456789012:client/sdk-nodejs-*" ] }
このclient
が何かというと、 --client_id basicPubSub
や --id basicPubSub
で渡しているクライアントIDです。
試しに許可されていないクライアントID(dummy
)を渡すと、Error: The connection was lost.
というエラーが発生しました。
$ mosquitto_pub -d \ --host a1b2c3-ats.iot.ap-northeast-1.amazonaws.com \ --id dummy \ ... Client dummy sending CONNECT Error: The connection was lost.
クライアントIDでclient/sdk-nodejs-*
にマッチする sdk-nodejs-dummy
と名乗ると、成功します。
$ mosquitto_pub -d \ --host a1b2c3-ats.iot.ap-northeast-1.amazonaws.com \ --id sdk-nodejs-dummy \ ... Client sdk-nodejs-dummy sending CONNECT Client sdk-nodejs-dummy received CONNACK (0) Client sdk-nodejs-dummy sending PUBLISH (d0, q0, r0, m1, 'sdk/test/python', ... (41 bytes)) Client sdk-nodejs-dummy sending DISCONNECT
モノ/証明書/ポリシーの関係
モノと証明書は多:多の関係であり、証明書とポリシーも多:多の関係です。
証明書の詳細ページからは、紐づいているポリシーとモノの一覧を確認できます。